package me.zhouzhuo810.stringsmanager.action;

import com.google.common.collect.Lists;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.vfs.VirtualFile;
import me.zhouzhuo810.stringsmanager.bean.StringEntity;
import me.zhouzhuo810.stringsmanager.utils.FileUtils;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;

public class StringsSortAction extends AnAction {
    @Override
    public void actionPerformed(AnActionEvent e) {

        VirtualFile file = e.getData(PlatformDataKeys.VIRTUAL_FILE);
        if (file == null) {
            showError("找不到目标文件");
            return;
        }

        if (file.isDirectory()) {
            showError("请选择strings.xml 或 arrays.xml文件");
            return;
        } else if (!file.getName().endsWith(".xml")) {
            showError("请选择strings.xml 或 arrays.xml文件");
            return;
        } else if (!file.getName().contains("strings") || !file.getName().contains("arrays")) {
            showError("请选择strings.xml 或 arrays.xml文件");
            return;
        }

        if (file.getParent().getName().equalsIgnoreCase("values")) {
            showError("请选择其他语言的strings.xml 或 arrays.xml文件");
            return;
        }

        //其他语言的Strings
        LinkedHashMap<String, StringEntity> keyValues = new LinkedHashMap<>();
        parseKeyValues(file, keyValues);

        //默认语言的Strings
        VirtualFile resDir = file.getParent().getParent();
        if (resDir.getName().equalsIgnoreCase("res")) {
            VirtualFile[] chids = resDir.getChildren();
            for (VirtualFile chid : chids) {
                if (chid.getName().equals("values")) {
                    if (chid.isDirectory()) {
                        VirtualFile[] values = chid.getChildren();
                        for (VirtualFile value : values) {
                            if (value.getName().equals("strings.xml")) {
                                LinkedHashMap<String, StringEntity> keyValuesDef = new LinkedHashMap<>();
                                parseKeyValues(value, keyValuesDef);
                                String content = sortKeyValuesToStrings(keyValuesDef, keyValues);
                                FileUtils.replaceContentToFile(file.getPath(), content);
                            } else if (value.getName().equals("arrays.xml")) {
                                LinkedHashMap<String, StringEntity> keyValuesDef = new LinkedHashMap<>();
                                parseKeyValues(value, keyValuesDef);
                                String content = sortKeyValuesToStrings(keyValuesDef, keyValues);
                                FileUtils.replaceContentToFile(file.getPath(), content);
                            }
                        }
                    }
                }
            }
        }

        e.getActionManager().getAction(IdeActions.ACTION_SYNCHRONIZE).actionPerformed(e);
    }

    private String sortKeyValuesToStrings(LinkedHashMap<String, StringEntity> keyValuesDef, LinkedHashMap<String, StringEntity> keyValues) {
        Set<String> keys = keyValuesDef.keySet();
        StringBuilder sb = new StringBuilder();
        sb.append("<resources>\n");
        for (String key : keys) {
            StringEntity value = keyValues.get(key);
            if (value.isArrays()) {
                sb.append(value.getValue());
            } else {
                sb.append("    <string name=\"").append(key).append("\">").append(value.getValue()).append("</string>\n");
            }
        }
        sb.append("</resources>\n");
        return sb.toString();
    }


    private void parseKeyValues(VirtualFile file, LinkedHashMap<String, StringEntity> keyValues) {
        List<StringEntity> strings;
        InputStream is = null;
        try {
            is = file.getInputStream();
            strings = extraStringEntity(is);
            if (strings != null) {
                for (StringEntity string : strings) {
                    keyValues.put(string.getId(), string);
                }
            }
        } catch (IOException e1) {
            e1.printStackTrace();
        } finally {
            FileUtils.closeQuietly(is);
        }

    }

    private List<StringEntity> extraStringEntity(InputStream is) {
        List<StringEntity> strings = Lists.newArrayList();
        try {
            return generateStrings(DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is), strings);
        } catch (SAXException | IOException | ParserConfigurationException e) {
            throw new RuntimeException(e);
        }
    }

    private List<StringEntity> generateStrings(Node node, List<StringEntity> strings) {
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            if (node.getNodeName().equals("string")) {
                String key = node.getAttributes().getNamedItem("name").getNodeValue();
                String value = node.getTextContent();
                strings.add(new StringEntity(key, value, false));
            } else if (node.getNodeName().equals("string-array")) {
                String key = node.getAttributes().getNamedItem("name").getNodeValue();
                NodeList childNodes = node.getChildNodes();
                StringBuilder sb = new StringBuilder();
                sb.append("<string-array name=\"" + key + "\">\n");
                for (int i = 0; i < childNodes.getLength(); i++) {
                    Node item = childNodes.item(i);
                    if (item.getNodeName().equals("item")) {
                        sb.append("        <item>" + item.getTextContent() + "</item>").append("\n");
                    }
                }
                sb.append("    </string-array>\n\n");
                strings.add(new StringEntity(key, sb.toString(), true));
            } else {
                NodeList children = node.getChildNodes();
                for (int j = 0; j < children.getLength(); j++) {
                    generateStrings(children.item(j), strings);
                }
            }
        } else {
            NodeList children = node.getChildNodes();
            for (int j = 0; j < children.getLength(); j++) {
                generateStrings(children.item(j), strings);
            }
        }
        return strings;
    }


    private void showError(String msg) {
        Notifications.Bus.notify(new Notification("StringManager", "StringManager", msg, NotificationType.ERROR));
    }
}
